package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_LATEST_LEARN_TIME;


/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author dayu
 * @since 2024-08-20
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
  private final CourseClient courseClient;
  private final CatalogueClient catalogueClient;
  private final LearningRecordMapper recordMapper;

  @Override
  public PageDTO<LearningLessonVO> queryMyLearningLessonPage(PageQuery pageQuery) {
    // 1、获取当前登录人ID
    Long userId = UserContext.getUser();
    log.info("{}", pageQuery);
    // 2.分页查询
    Page<LearningLesson> page = this.lambdaQuery()
            .eq(LearningLesson::getUserId, userId)
            .page(pageQuery.toMpPage(DATA_FIELD_NAME_LATEST_LEARN_TIME, pageQuery.getIsAsc()));

    List<LearningLesson> records = page.getRecords();
    if (ObjectUtil.isEmpty(records)) {
      return PageDTO.empty(page.getTotal(), page.getPages());
    }

    // 收集 id
    Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());

    //获取课程信息 （课程名称、封面、总课时数）
    List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
    // 转map
    Map<Long, CourseSimpleInfoDTO> courseInfoMap = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
    if (ObjectUtil.isEmpty(simpleInfoList)) {
      throw new BizIllegalException("课程信息不存在");
    }
    List<LearningLessonVO> result = new ArrayList<>();
    for (LearningLesson record : records) {
      LearningLessonVO vo = BeanUtil.toBean(record, LearningLessonVO.class);

//      for (CourseSimpleInfoDTO courseSimpleInfoDTO : simpleInfoList) {
//        if (record.getCourseId().equals(courseSimpleInfoDTO.getId())) {
//          vo.setCourseName(courseSimpleInfoDTO.getName());
//          vo.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
//          vo.setSections(courseSimpleInfoDTO.getSectionNum());
//        }
//      }
      // 去嵌套循环
      vo.setCourseName(courseInfoMap.get(record.getCourseId()).getName());
      vo.setCourseCoverUrl(courseInfoMap.get(record.getCourseId()).getCoverUrl());
      vo.setSections(courseInfoMap.get(record.getCourseId()).getSectionNum());
      result.add(vo);
    }
    return PageDTO.of(page, result);
  }

  @Override
  public void addUserLessons(Long userId, List<Long> courseIds) {
    // 1.查询课程有效期
    List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(courseIds);
    if (CollUtils.isEmpty(cInfoList)) {
      // 课程不存在，无法添加
      log.error("课程信息不存在，无法添加到课表");
      return;
    }
    // 构建条件
    LearningLesson learningLesson = new LearningLesson();
    // 设置添加人
    learningLesson.setUserId(userId);
    List<LearningLesson> learningLessons = new ArrayList<>();
    // 获取现在时间
    LocalDateTime now = LocalDateTime.now();
    for (CourseSimpleInfoDTO courseSimpleInfoDTO : cInfoList) {
      // 每个课程学习有效时间
      Integer validDuration = courseSimpleInfoDTO.getValidDuration();
      if (ObjectUtil.isEmpty(validDuration) || validDuration < 0 || validDuration > 9999) {
        continue;
      }
      // learningLesson.setCreateTime(now);
      // 设置过期时间 现在时间加上有效期月份
      learningLesson.setExpireTime(now.plusMonths(validDuration));
      // 设置课程id
      learningLesson.setCourseId(courseSimpleInfoDTO.getId());
      learningLessons.add(learningLesson);
    }
    //  加入课程
    saveBatch(learningLessons);

  }


  @Override
  public LearningLessonVO now() {
    // 1、获取当前登录人ID
    Long userid = UserContext.getUser();

    // 查询课程信息
    LearningLesson lesson = this.lambdaQuery()
            .eq(LearningLesson::getUserId, userid)
            .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
            .orderByDesc(LearningLesson::getLatestLearnTime)
            .last("limit 1")
            .one();
    if (lesson == null) {
      return null;
    }
    // 转vo
    LearningLessonVO vo = BeanUtil.toBean(lesson, LearningLessonVO.class);
    // 4.查询课程信息
    CourseFullInfoDTO cInfo = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
    if (cInfo == null) {
      throw new BadRequestException("课程不存在");
    }
    vo.setCourseName(cInfo.getName());
    vo.setCourseCoverUrl(cInfo.getCoverUrl());
    vo.setSections(cInfo.getSectionNum());
    // 课表中的课程总数
    Integer count = this.lambdaQuery()
            .eq(LearningLesson::getUserId, userid)
            .count();
    // 课程总数插值
    vo.setCourseAmount(count);
    // 查询小节信息
    List<CataSimpleInfoDTO> cataInfos =
            catalogueClient.batchQueryCatalogue(Arrays.asList(lesson.getLatestSectionId()));
    if (!CollUtils.isEmpty(cataInfos)) {
      CataSimpleInfoDTO cataInfo = cataInfos.get(0);
      vo.setLatestSectionName(cataInfo.getName());
      vo.setLatestSectionIndex(cataInfo.getCIndex());
    }
    return vo;
  }

  @Override
  public void delRefundCourse(Long courseId) {
    Long userid = UserContext.getUser();
    if (userid == null) {
      throw new BadRequestException("用户未登录");
    }
    removeById(buildUserIdAndCourseIdWrapper(userid, courseId));
  }

  @Override
  public void delRefundCourse(Long userId, Long courseId) {
    removeById(buildUserIdAndCourseIdWrapper(userId, courseId));
  }

  @Override
  public Long isLessonValid(Long courseId) {
    return this.lambdaQuery()
            .select(LearningLesson::getId)
            .eq(LearningLesson::getCourseId, courseId)
            .eq(LearningLesson::getUserId, UserContext.getUser())
            .ne(LearningLesson::getStatus, LessonStatus.EXPIRED.getValue())
            .oneOpt()
            .map(LearningLesson::getId) // 从结果中提取 id
            .orElseThrow(() -> new BadRequestException("课程不存在"));
  }

  @Override
  public LearningLessonVO getCourse(Long courseId) {
    LearningLesson learningLesson = this.lambdaQuery()
            .select(LearningLesson::getId,
                    LearningLesson::getCourseId,
                    LearningLesson::getStatus,
                    LearningLesson::getLearnedSections,
                    LearningLesson::getCreateTime,
                    LearningLesson::getExpireTime)
            .eq(LearningLesson::getCourseId, courseId)
            .eq(LearningLesson::getUserId, UserContext.getUser())
            .ne(LearningLesson::getStatus, LessonStatus.EXPIRED.getValue())
            .oneOpt()
            .orElseThrow(() -> new BadRequestException("课程不存在"));
    return BeanUtil.toBean(learningLesson, LearningLessonVO.class);
  }

  @Override
  public Integer countLearningLessonByCourse(Long courseId) {
    return this.lambdaQuery().eq(LearningLesson::getCourseId, courseId).count();
  }

  @Override
  public LearningLesson queryByUserAndCourseId(Long userId, Long courseId) {
    return getOne(buildUserIdAndCourseIdWrapper(userId, courseId));
  }

  @Override
  public void createLearningPlan(Long courseId, Integer freq) {
    LearningLesson lesson = getOne(buildUserIdAndCourseIdWrapper(UserContext.getUser(), courseId));
    AssertUtils.isNotNull(lesson, "课表数据不存在，无法更新数据");
    lambdaUpdate()
            .eq(LearningLesson::getCourseId, courseId)
            .set(lesson.getPlanStatus() == PlanStatus.NO_PLAN,LearningLesson::getPlanStatus, LessonStatus.LEARNING)
            .set(LearningLesson::getWeekFreq, freq)
            .update();
  }

  @Override
  public LearningPlanPageVO queryMyPlans(PageQuery pageQuery) {
    LearningPlanPageVO vo = new LearningPlanPageVO();
    // 1、获取当前登录用户
    Long userId = UserContext.getUser();

    // 2、分页查询我的课表
    // select * from learning_lesson where user_id = ? and plan_status = 1 and status in (0, 1) order by latest_learn_time desc limit 0,10
    Page<LearningLesson> pageResut = this.lambdaQuery()
            .eq(LearningLesson::getUserId, userId)
            .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
            .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
            .page(pageQuery.toMpPage("latest_learn_time", false));
    List<LearningLesson> records = pageResut.getRecords();
    if (ObjectUtil.isEmpty(records)) {
      return vo.emptyPage(pageResut);
    }

    // 3、根据课程ID集合查询课程信息
    Map<Long, CourseSimpleInfoDTO> courseInfoMap = queryCourseInfoAnd2Map(records);

    // 4、统计学习记录中本周学习小节数据
    // select r.`lesson_id`,count(*) as num from learning_record r where r.`user_id` = 2 and r.`finished` = 1
    // and r.`finish_time` between '2024-08-19 00:00:00' and '2024-08-25 23:59:59'  group by r.`lesson_id`
    // 4.1、获取本周开始、结束日期
    LocalDateTime begin = DateUtils.getWeekBeginTime(LocalDate.now());
    LocalDateTime end = DateUtils.getWeekEndTime(LocalDate.now());

    // 4.2、发起分组统计
    QueryWrapper<LearningRecord> queryWrapper = new QueryWrapper<>();
    queryWrapper
            .select("lesson_id as id,COUNT(*) AS num")
            .eq("user_id", userId)
            .eq("finished", true)
            .between("finish_time", begin, end)
            .groupBy("lesson_id");
    List<Map<String, Object>> mapList = recordMapper.selectMaps(queryWrapper);
    Map<Long, Long> learnedSectionNumMap = mapList.stream().collect(Collectors.toMap(r -> (Long) r.get("id"), r -> (Long) r.get("num")));

    // 5、循环之前查询的分页课表数据，填充数据
    List<LearningPlanVO> voList = new ArrayList<>(records.size());
    for (LearningLesson record : records) {
      // 5.1、拷贝po至vo
      LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);

      // 5.2、填充课程数据
      CourseSimpleInfoDTO courseInfo = courseInfoMap.get(record.getCourseId());
      if (ObjectUtil.isNotEmpty(courseInfo)) {
        learningPlanVO.setCourseName(courseInfo.getName());
        learningPlanVO.setSections(courseInfo.getSectionNum());
      }

      // 5.3、填充本周已学习小节数
      learningPlanVO.setWeekLearnedSections(learnedSectionNumMap.getOrDefault(record.getId(),0L).intValue());

      // 5.4、添加vo至volist
      voList.add(learningPlanVO);
    }

    // 6、计算本周计划学习的总小节数
    // select sum(week_freq) from learning_lesson where user_id = ? and plan_status = 1 and status in (0,1);
    LearningLesson lesson = this.query()
            .select("sum(week_freq) as total_weekfreq")
            .eq("user_id", userId)
            .eq("plan_status", PlanStatus.PLAN_RUNNING)
            .in("status", LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
            .one();

    // 7、计算本周已学习的总小节数
    long sum = learnedSectionNumMap.values().stream().mapToLong(l -> l.longValue()).sum();
    Integer weekFinished = Long.valueOf(sum).intValue();

    // 8、封装vo并返回
    vo.setWeekTotalPlan(lesson.getTotalWeekfreq());
    vo.setWeekFinished(weekFinished);
    vo.setWeekPoints(null); // TODO 本周学习积分

    return vo.pageInfo(pageResut.getTotal(),pageResut.getPages(),voList);
  }

  /**
   * 收集 records 中的courseId，进行远程调用，获取课程信息并转换为Map
   *
   * @param records
   * @return
   */
  private Map<Long, CourseSimpleInfoDTO> queryCourseInfoAnd2Map(List<LearningLesson> records) {
    // 3.1、收集当前页码的所有课程ID集合
    Set<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());

    // 3.2、发起远程调用
    List<CourseSimpleInfoDTO> courseInfoList = courseClient.getSimpleInfoList(courseIds);

    // 3.3、健壮性判断
    if (ObjectUtil.isEmpty(courseInfoList)) {
      throw new BizIllegalException("课程信息不存在");
    }

    //3.4、将list转换成map，供后续高效使用
    Map<Long, CourseSimpleInfoDTO> courseInfoMap = courseInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, Function.identity()));
    return courseInfoMap;
  }
  private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
    LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
            .lambda()
            .eq(LearningLesson::getUserId, userId)
            .eq(LearningLesson::getCourseId, courseId);
    return queryWrapper;
  }
}
